In object oriented programming, 
tightly coupled objects / classes often result in an untestable, and a difficult to manage code base. 
These tightly coupled classes can be re-factored, and coupling can be achieved through DI (Dependency Injection). 
Every object should be assigned one and only one responsibility

Single Responsibility Principle:
In object-oriented programming, the single responsibility principle states that every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility.

Separation Of Concerns:
In computer science, separation of concerns (SoC) is a design principle for separating a computer program into distinct sections, such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program. A concern can be as general as the details of the hardware the code is being optimized for, or as specific as the name of a class to instantiate.

Consider the following Product class which uses a database to store and retrieve products:
<?php
class Product 
{    
    protected $db;
    protected $name;
    protected $price;
     
    public function __construct($dbParams)
    {
    	$this->db = new Db($dbParams);
    }
     
    public function getProductById($id)
    {
    	return $this->db->findById($id);
    }
}
     
$product = new Product($dbParams);
?>
In the above code example the Product class is violating the principle of single responsibility, 
the __construct function is receiving an argument $dbParams which has nothing to do with the Product itself: 
it is not the responsibility of a Product to create and manage databases. 
Also, the __construct is compromising the independence of the Product by introducing an acquaintance relationship with DB class (tight coupling).
  

For a large project, this approach has at least two issues:
- Testing can be a very time consuming and a difficult task.
- Tightly coupled classes will make it difficult to manage your code base: a change in one class will affect the behavior of other classes.
    
Decoupling Through Dependency Injection
Dependency injection is about taking the responsibility of creating and injecting class dependencies.We can decouple Product class from DB class by providing a DB object through Product's constructor.
<?php
class Product 
{    
    protected $db;
    protected $name;
    protected $price;
     
    public function __construct($db)
    {
    	$this->db = $db;
    }
     
    public function getProductById($id)
    {
    	return $this->db->findById($id);
    }
}
     
$db = new Db($dbParams);// creating DB object
$product = new Product($db);//injecting DB object through constructor
?>

    